#include "Texture.h"
#include <SERender/Util/Util.h>
#include <glad/glad.h>
#include <SERender/Resourses/Loader/TextureLoader.h>

namespace SEngine
{

    Texture::Texture()
    { 
        glCall(glGenTextures(1, &m_id)); 
    }

    Texture::~Texture()
    { 
        glDeleteTextures(1, &m_id); 
    }

    void Texture2D::Bind(int slot)
    { 
        m_slot = slot; 
        glActiveTexture(GL_TEXTURE0 + m_slot); 
        glBindTexture(GL_TEXTURE_2D, m_id); 
    }

    void Texture2D::Unbind()
    { 
        glActiveTexture(GL_TEXTURE0 + m_slot); 
        glBindTexture(GL_TEXTURE_2D, 0); 
    }

    std::shared_ptr<Texture2D> Texture2D::GetDefaultTexture()
    {
        static std::shared_ptr<Texture2D> tex;
        if (!tex) {
            TextureLoader<Texture2D> loader;
            loader.SetInternalFormat(RGBA16F);
            loader.SetFormat(RGBA);
            loader.SetType(FLOAT);
            loader.SetParameter(TEXTURE_MAG_FILTER, LINEAR);
            loader.SetParameter(TEXTURE_MIN_FILTER, LINEAR);
            loader.SetParameter(TEXTURE_WRAP_S, CLAMP_TO_EDGE);
            loader.SetParameter(TEXTURE_WRAP_T, CLAMP_TO_EDGE);
            float buffer[] = {0.0f, 0.0f, 0.0f, 0.0f};
            tex = loader.CreateTexture(1, 1, buffer);
        }
        return tex;
    }

    void Texture2DMultiSample::Bind(int slot)
    {
        m_slot = slot; 
        glActiveTexture(GL_TEXTURE0 + m_slot); 
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_id);
    }

    void Texture2DMultiSample::Unbind()
    {
        glActiveTexture(GL_TEXTURE0 + m_slot); 
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); 
    }

    void TextureCube::Bind(int slot)
    {
        m_slot = slot; 
        glActiveTexture(GL_TEXTURE0 + m_slot); 
        glBindTexture(GL_TEXTURE_CUBE_MAP, m_id); 
    }

    void TextureCube::Unbind()
    {
        glActiveTexture(GL_TEXTURE0 + m_slot); 
        glBindTexture(GL_TEXTURE_CUBE_MAP, 0); 
    }

    std::shared_ptr<TextureCube> TextureCube::GetDefaultTexture()
    {
        static std::shared_ptr<TextureCube> tex;
        if (!tex) {
            glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
            TextureLoader<TextureCube> loader;
            loader.SetInternalFormat(RGBA16F);
            loader.SetFormat(RGBA);
            loader.SetType(FLOAT);
            loader.SetParameter(TEXTURE_WRAP_S, CLAMP_TO_EDGE);
            loader.SetParameter(TEXTURE_WRAP_T, CLAMP_TO_EDGE);
            loader.SetParameter(TEXTURE_WRAP_R, CLAMP_TO_EDGE);
            loader.SetParameter(TEXTURE_MIN_FILTER, LINEAR);
            loader.SetParameter(TEXTURE_MAG_FILTER, LINEAR);
            float buffer[] = {0.0f, 0.0f, 0.0f, 0.0f};
            tex = loader.CreateTexture(1, 1, buffer);
        }
        return tex;
    }

    void Texture3D::Bind(int slot)
    {
        m_slot = slot; 
        glActiveTexture(GL_TEXTURE0 + m_slot); 
        glBindTexture(GL_TEXTURE_3D, m_id); 
    }
    
    void Texture3D::Unbind()
    {
        glActiveTexture(GL_TEXTURE0 + m_slot);
        glBindTexture(GL_TEXTURE_3D, 0);
    }

} // namespace SEngine
